/**
 * Esta clase representa a un envio en forma abstracta que se a generado
 * a traves de una venta a domicilio.
 */

package envios;

import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;

import estadosDelEnvio.EstadoDeEnvio;
import estadosDelEnvio.PendienteDeEnvio;
import exceptions.StatesException;
import ventas.VentaConEnvio;

/**
 * @author Lucas Alan Silvestri.
 *
 */

public abstract class Envio {
	
	private EstadoDeEnvio estado;
	private VentaConEnvio ventaRealizada;
	private DateTime fecha;
	private List<DateTime> historialDeFechas;
	private String domicilio;
	
	/**
	 * @param ventaRealizada - Venta realizada en la sucursal.
	 */
	public Envio(VentaConEnvio ventaRealizada){
		this.setVentaRealizada(ventaRealizada);
		this.setEstado(new PendienteDeEnvio());
		new DateTime();
		this.setFecha(DateTime.now());
		this.setHistorialDeFechas(new ArrayList<DateTime>());
		this.setDomicilio(
				this.getVentaRealizada().getClienteQueDeseaRealizarLaCompra().getDomicilio());
	}

	/**
	 * Comienza el proceso de envio.
	 * @throws StatesException
	 */
	public void enviar() throws StatesException{
		this.getEstado().enviarEnvio(this);
		}
	
	/**
	 * Cancela el envio.
	 * @throws StatesException
	 */
	public void cancelar() throws StatesException{
		this.getEstado().cancelarEnvio(this);
	}
	
	/**
	 * Si el envio ya fue pagado, lo entregara a domicilio
	 * en caso contrario, el cliente debera abonarlo.
	 * @throws StatesException
	 */
	public void entregar() throws StatesException{
		this.getEstado().entregarEnvio(this);
	}
	
	/**
	 * Reprograma el envio.
	 */
	public void reprogramar(DateTime fechaAReprogramar){
		this.getHistorialDeFechas().add(this.getFecha());
		this.setFecha(fechaAReprogramar);
	}
	
	/**
	 * Retorna los productos que estaban siendo enviados a la
	 * sucursal de compra.
	 */
	public void devolverProductos() {
		this.getVentaRealizada().devolverProductos();
	}
	
	/**
	 * @return si el envio se encuentra pendiente de envio.
	 */
	public boolean estaPendienteDeEnvio(){
		return this.getEstado().estoyPendienteDeEnvio();
	}
	
	/**
	 * @return si el envio se encuentra en proceso de envio.
	 */
	public boolean estaEnProcesoDeEnvio() {
		return this.getEstado().estoyEnProcesoDeEnvio();
	}
	
	/**
	 * @return si el envio se encuentra cancelado.
	 */
	public boolean estaCancelado() {
		return this.getEstado().estoyCancelado();
	}
	
	/** 
	 * @return si el envio se encuentra entregado.
	 */
	public boolean estaEntregado() {
		return this.getEstado().estoyEntregado();
	}
	
	/**
	 * Cambia el estado en el que se encuentra el envio.
	 * @param estado
	 */
	public void cambiarEstado(EstadoDeEnvio estado){
		this.setEstado(estado);
	}
	
	/**
	 * Retorna el estado en el que se encuentra el envio.
	 * @return
	 */
	public EstadoDeEnvio getEstado() {
		return estado;
	}

	/**
	 * Establece el estado en el que se encuentra el envio.
	 * @param estado
	 */
	protected void setEstado(EstadoDeEnvio estado) {
		this.estado = estado;
	}

	/**
	 * Retorna la venta realizada por la cual se creo el envio.
	 * @return
	 */
	public VentaConEnvio getVentaRealizada() {
		return ventaRealizada;
	}

	/**
	 * Establece la venta asociada al envio.
	 * @param ventaRealizada.
	 */
	protected void setVentaRealizada(VentaConEnvio ventaRealizada) {
		this.ventaRealizada = ventaRealizada;
	}

	/**
	 * Retorna la fecha de la venta realizada por la cual se creo el envio.
	 * @return
	 */
	public DateTime getFecha() {
		return fecha;
	}

	/**
	 * Establece la fecha asociada al envio.
	 * @param fecha
	 */
	protected void setFecha(DateTime fecha) {
		this.fecha = fecha;
	}

	/**
	 * Retorna el historial de fechas por las que paso el envio.
	 * @return
	 */
	public List<DateTime> getHistorialDeFechas() {
		return historialDeFechas;
	}

	/**
	 * Establece el historial de fechas por las que paso el envio.
	 * @param historialDeFechas
	 */
	protected void setHistorialDeFechas(List<DateTime> historialDeFechas) {
		this.historialDeFechas = historialDeFechas;
	}

	/**
	 * @return el domicilio del cliente.
	 */
	protected String getDomicilio() {
		return domicilio;
	}

	/**
	 * @param domicilio es el domicilio del cliente.
	 */
	protected void setDomicilio(String domicilio) {
		this.domicilio = domicilio;
	}
}
